package enums

import (
	"fmt"
	"github.com/xuri/excelize/v2"
	"sort"
	"strings"
)

type EnumOption[T IntConstraint] struct {
	ValueColNum                             int
	NameColNum                              int
	ExcelFilePath, GenFilename, GenEnumName string
	Sheet                                   string
	AnnoConnectionSymbol                    string
	TranConnectionSymbol                    string
	ConstNameOpt                            ConstNameOpt
	ValueOpt                                ValueOpt[T]
	AnnotationColNums                       []int
	TranColNums                             []int
}

type (
	ConstNameOpt              func(constName string) string
	ValueOpt[T IntConstraint] func(colValue string) T
)

func GenerationEnumsCodeFormExcel[T IntConstraint](enumOption EnumOption[T]) error {
	sort.Ints(enumOption.TranColNums)
	sort.Ints(enumOption.AnnotationColNums)

	f, err := excelize.OpenFile(enumOption.ExcelFilePath)
	if err != nil {
		return err
	}
	defer func() {
		// Close the spreadsheet.
		if err = f.Close(); err != nil {
			fmt.Println(err)
		}
	}()

	// get data form excel
	rows, err := f.GetRows("Sheet1")
	if err != nil {
		return err
	}
	// new enum form excel
	var enums []EnumConst[T]
	for _, row := range rows {
		var e EnumConst[T]
		annoBuilder := strings.Builder{}
		valueBuilder := strings.Builder{}
		nameBuilder := strings.Builder{}
		tranBuilder := strings.Builder{}
		for i, colCell := range row {
			if i != 0 && i != len(row)-1 {
				// valueBuilder.WriteString(enumOption.ValueConnectionSymbol)
				annoBuilder.WriteString(enumOption.AnnoConnectionSymbol)
				tranBuilder.WriteString(enumOption.TranConnectionSymbol)
				//nameBuilder.WriteString(enumOption.NameConnectionSymbol)
			}
			col := colCell
			if i == enumOption.ValueColNum {
				valueBuilder.WriteString(col)
			}
			if i == enumOption.NameColNum {
				nameBuilder.WriteString(col)
			}

			if search(enumOption.AnnotationColNums, i) {
				annoBuilder.WriteString(col)
			}
			if search(enumOption.TranColNums, i) {
				tranBuilder.WriteString(col)
			}

		}

		// get EnumConst
		e.Name = enumOption.ConstNameOpt(nameBuilder.String())
		e.Value = enumOption.ValueOpt(valueBuilder.String())
		e.Tran = tranBuilder.String()
		e.Annotation = annoBuilder.String()
		enums = append(enums, e)
	}

	if err = GenerationEnumsCode(enumOption.GenFilename, enumOption.GenEnumName, enums); err != nil {
		return err
	}
	return nil
}

func search(colNums []int, target int) bool {
	if colNums == nil || len(colNums) < 1 {
		return false
	}
	index := sort.SearchInts(colNums, target)
	if index < len(colNums) && colNums[index] == target {
		return true
	}
	return false
}
